/*
 * log_thread.cpp
 *
 *  Created on: 2013-12-19
 *      Author: lixingyi
 */

#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>


#include "framework/network_util.h"
#include "framework/time_util.h"
#include "framework/system_util.h"

#include "log_thread.h"


#define time_printf(fmt,args...) do{printf("%ld," fmt,time_ms(),##args) ; }while(0)

using namespace kingnet ;


static const char* LEVEL_STR[] =
{
    "critical" ,
    "error" ,
    "warn" ,
    "info" ,
    "debug" ,
    ""
} ;


/*
void log_record_insert(LogRecord* prev,LogRecord* curr,LogRecord* next)
{
    prev->next = curr ;

    curr->prev = prev ;
    curr->next = next ;

    next->prev = curr ;
}
void log_record_remove(LogRecord* curr)
{
    curr->prev->next = curr->next ;
    curr->next->prev = curr->prev ;
    //curr->next = curr->prev = NULL ;
}
*/

LogThread::LogThread():m_head(NULL),m_tail(NULL),m_fd(-1),m_filedate(0)
{
    // TODO Auto-generated constructor stub
    //m_head.next = m_head.prev = &m_head ;

    pthread_mutex_init(&m_mutex,NULL);
    pthread_cond_init(&m_cond,NULL);
    pthread_mutex_init(&m_file_lock,NULL);
}

LogThread::~LogThread()
{
    // TODO Auto-generated destructor stub

    pthread_cond_destroy(&m_cond); 
    pthread_mutex_destroy(&m_mutex); 
    pthread_mutex_destroy(&m_file_lock); 
}



int LogThread::on_init()
{

    if(prepare()!=0) return -1 ;

    
   
    m_last_time = 0 ;
    m_reload_time = 0 ;
    set_thread_title("log_thread");

    return 0 ;
}

void LogThread::on_fini()
{
    run_once() ;
    
    if(m_fd >= 0) 
    {
        close(m_fd) ;
        m_fd = -1 ;
        
    }

}



void LogThread::run_once()
{
    int now_time = time(0) ;
    if(now_time - m_last_time > 60)
    {
        m_last_time = now_time ;
        on_timer() ;
    }

    
    /*
    while(m_head.next != &m_head)
    {
        LogRecord* curr = m_head.next ;
        log_record_remove(curr);
        flush_log(curr) ;
        delete curr ;
    }
    */

    if( m_head )
    {
        LogRecord* head = NULL ;
        pthread_mutex_lock(&m_mutex) ;
        head = m_head ;
        m_head = NULL ;
        m_tail = NULL ;
        pthread_mutex_unlock(&m_mutex) ;
        LogRecord* prev = NULL ;
        while(head)
        {
            flush_log(head) ;
            prev = head ;
            head = head->next ;
            free(prev) ;
        }

    }
    else
    {
        //empty
        usleep(1000) ;
    }


    
}

int LogThread::write_log(int ll,const char* fmt,...)
{
    if( !running() ) return -1 ;

    if ( m_fd < 0 || ll < 0 || ll > m_level) return -1 ;

    const int MAX_RECORD_SIZE = 4000 ;
    LogRecord* record = (LogRecord*)malloc(MAX_RECORD_SIZE ) ;
    if(record == NULL ) return -1 ;
    record->total_size = MAX_RECORD_SIZE - sizeof(*record) -1 ;
    record->data_size = 0 ;

    va_list ap ;
    va_start(ap, fmt);
    int length = vsnprintf(record->data,record->total_size,fmt,ap) ;
    va_end(ap);

    if(length < 0 ) 
    {
        free(record) ;
        return -1 ;
    }
    else if ( length >= record->total_size) 
    {
        length =record->total_size - 1 ;
    }

    //append '\n'
    if( record->data[length-1] !='\n')
    {
        record->data[length]= '\n' ;
        record->data[length+1]= '\0' ;
        ++length ;
    }
    record->data_size = length ;
    
    record->next = NULL ;
    record->level = ll ;
    pthread_mutex_lock(&m_mutex) ;
    //log_record_insert(m_head.prev,record,&m_head) ;
    if(m_tail == NULL)
    { 
        m_head = m_tail = record ;
    }
    else
    {
        m_tail->next = record ;
        m_tail = record ;
    }
    pthread_mutex_unlock(&m_mutex) ;
    
    return 0 ;
}

int LogThread::prepare()
{
    time_t t = time(NULL);
    localtime_r(&t, &m_now)  ;
    m_now.tm_year += 1900 ;
    m_now.tm_mon += 1 ;

    int curdate = ( m_now.tm_mon << 8 ) | m_now.tm_mday ;
    if (m_filedate != curdate )
    {
        char filename[2048] = {0} ;
        if(strcmp(m_prefix.c_str(),"/dev/null")==0)  return 0 ;

        pthread_mutex_lock(&m_file_lock) ;

        snprintf(filename,sizeof(filename),"%s-%04d-%02d-%02d.log",m_prefix.c_str()
                ,m_now.tm_year,m_now.tm_mon,m_now.tm_mday) ;

        pthread_mutex_unlock(&m_file_lock) ;

        int fd = open(filename,O_APPEND|O_WRONLY|O_CREAT,0755) ;
        if ( fd < 0 ) return -1;
        if ( m_fd >= 0 )
        {
            //flush() ;
            close(m_fd) ;
        }
        m_fd = fd ;
        m_filedate = curdate ;
    }

    return 0 ;

}

void LogThread::flush_log(LogRecord* record)
{
    if ( prepare() != 0 ) return ;

    char buf[64] ;
    int length = sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d,%s," ,
            m_now.tm_year,m_now.tm_mon,m_now.tm_mday,
            m_now.tm_hour,m_now.tm_min,m_now.tm_sec ,LEVEL_STR[record->level]) ;

    write(m_fd,buf,length) ;
    write(m_fd,record->data,record->data_size) ;

}





void LogThread::on_timer()
{
}



